package com.ls.io.rpc.proxy;

import com.alibaba.fastjson.JSON;
import com.ls.io.rpc.protobuf.RpcPackage;
import com.ls.io.rpc.transport.ClientFactory;
import com.ls.io.rpc.transport.ClientPool;
import com.ls.io.rpc.transport.ResponseContext;
import com.ls.io.rpc.protobuf.RpcContent;
import com.ls.io.rpc.protobuf.RpcHeader;
import com.ls.io.rpc.utils.ReqIdUtils;
import com.ls.io.rpc.utils.SeriUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;

public class RpcInvocationHandler<T> implements InvocationHandler {

    private Class<T> interfaceName;

    public RpcInvocationHandler(Class<T> interfaceName) {
        this.interfaceName = interfaceName;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 1. 封装消息
        RpcContent content = new RpcContent();
        content.setIfcName(interfaceName.getName());
        content.setMethodName(method.getName());
        content.setArgs(args);
        content.setParameterTypes(method.getParameterTypes());

        RpcHeader header = createHeader();
        header.setRequestId((long)args[1]);

        RpcPackage pck = new RpcPackage(header, content);

        // 2. 从连接池获取链接
        ClientPool pool = ClientFactory.getPool(new InetSocketAddress("localhost", 9000));
        NioSocketChannel client = pool.getClient();
//        System.out.println("pool: " + pool + ", " + "client: " + client);

        // 3. 调用远程
        CompletableFuture response = ResponseContext.addRequest(header.getRequestId());

        ChannelFuture channelFuture = client.writeAndFlush(pck);
        pool.back(client); // 归还回连接池

//        System.out.println("requestId :" + header.getRequestId() + ", length: " + body.length);

        // 4. 等待返回结果
        Object result = response.get();
        return result;
    }

    public RpcHeader createHeader(){
        RpcHeader header = new RpcHeader();
        header.setFlag(111);
        header.setRequestId(ReqIdUtils.id());
//        header.setLength(body.length);
        return header;
    }
}